#include "StdAfx.h"
#include "RunConfiguration.h"
#include <Shlwapi.h>


RunConfiguration::RunConfiguration(void) :
    m_listOperation(false),
    m_selfTest(false),
    m_argc(0)
{
}

RunConfiguration::~RunConfiguration(void)
{
    DeleteArgv();
}

void RunConfiguration::Parse(int argc, _TCHAR* argv[])
{
    DeleteArgv();

    tstring currentArg;

    for (int i = 0; i < argc; ++i) {
        currentArg = argv[i];

        if (currentArg.find(_T("--gtest_filter=")) == 0) {
            m_filter = currentArg.substr(15);
        }
        else if (currentArg.find(_T("--pipename=")) == 0) {
            m_pipeName = currentArg.substr(11);

            if (! m_pipeName.empty() && m_pipeName[0] != '\\') {
                // assume the name was provided without the local pipe prefix
                m_pipeName = _T("\\\\.\\pipe\\") + m_pipeName;
            }
        }
        else if (currentArg.find(_T("--testlib=")) == 0) {
            m_testLib = currentArg.substr(10);
        }
        else if (currentArg.find(_T("--libdir=")) == 0) {
            m_libDir = currentArg.substr(9);
        }
        else if (currentArg == _T("--gtest_list_tests")) {
            m_listOperation = true;
        }
        else if (currentArg == _T("--selftest")) {
            m_selfTest = true;
        }
    }

    if (! m_selfTest) {
        // add the exclusion filter

        if (m_filter.empty()) {
            m_filter = _T("-GTestRunnerTest.*");
        }
        else {
            if (m_filter.find(_T('-')) == tstring::npos) {
                m_filter += _T("-GTestRunnerTest.*");
            }
            else {
                m_filter += _T(":GTestRunnerTest.*");
            }
        }

        // exclude fixture-based tests explicitly here
        m_filter += _T(":PipingListenerTests.*");
    }

    CreateArgv(argc, argv);
}


tstring RunConfiguration::GetFilter() const
{
    return m_filter;
}

tstring RunConfiguration::GetPipeName() const
{
    return m_pipeName;
}

tstring RunConfiguration::GetTestLib() const
{
    return m_testLib;
}

tstring RunConfiguration::GetLibDir() const
{
    if (! m_libDir.empty()) {
        return m_libDir;
    }

    TCHAR path[MAX_PATH + 1];

    if (GetFullPathName(m_testLib.c_str(), MAX_PATH + 1, path, NULL) != 0) {
        if (PathRemoveFileSpec(path)) {
            return path;
        }
    }

    return _T(".");
}

bool RunConfiguration::IsSelfTest() const
{
    return m_selfTest;
}

bool RunConfiguration::IsListOperation() const
{
    return m_listOperation;
}

int RunConfiguration::GetArgc() const
{
    return m_argc;
}

int* RunConfiguration::GetMutableArgc()
{
    return &m_argc;
}

_TCHAR** RunConfiguration::GetArgv()
{
    return m_argv;
}

void RunConfiguration::CreateArgv(int argc, _TCHAR* argv[])
{
    int i;
    tstring currentArg;
    bool needFilter = ! IsSelfTest();

    if (needFilter) {
        for (i = 0; i < argc; ++i) {
            currentArg = argv[i];

            if (currentArg.find(_T("--gtest_filter=")) == 0) {
                needFilter = false;
                break;
            }
        }
    }

    if (needFilter) {
        ++argc;
    }

    m_argc = argc;
    m_argv = new _TCHAR*[argc];

    for (i = 0; i < argc; ++i) {
        // if we encounter the filter as a flag, add our own filter value. If
        // we need it but we don't encounter it, add it at the end of the
        // command line.
        if ((needFilter && i == argc - 1) || (tstring(argv[i]).find(_T("--gtest_filter=")) == 0)) {
            currentArg = _T("--gtest_filter=") + m_filter;

            m_argv[i] = new _TCHAR[currentArg.size()+1];
            currentArg.copy(m_argv[i], currentArg.size(), 0);
            m_argv[i][currentArg.size()] = '\0';
        }
        else {
            currentArg = argv[i];

            m_argv[i] = new _TCHAR[currentArg.size()+1];
            currentArg.copy(m_argv[i], currentArg.size(), 0);
            m_argv[i][currentArg.size()] = '\0';
        }
    }
}

void RunConfiguration::DeleteArgv()
{
    if (m_argc > 0) {
        for (int i = 0; i < m_argc; ++i) {
            delete m_argv[i];
        }

        delete[] m_argv;
        m_argc = 0;
    }
}